namespace ScrumSprintMonitor.UI.Wpf
{
    #region #using Directives

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;

    using Design;

    using Infrastructure;
    using Infrastructure.Configuration;
    using Infrastructure.IoC;

    using Microsoft.Practices.Unity;

    using Properties;

    using Rhino.Mocks;

    using ViewModels;

    #endregion

    public class UnityUiDesignTimeModule : StandardModule
    {
        /// <summary>
        ///   Loads the module into the container.
        /// </summary>
        public override void Load()
        {
            try
            {
                SetupDesignTimeBindings();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, GetType().FullName);

                throw;
            }
        }

        private void SetupDesignTimeBindings()
        {
            Container.RegisterType<IPresentationConfiguration, TestAssetLibrary.HardcodedPresentationConfiguration>(
                new ContainerControlledLifetimeManager());

            var monitorViewModel = MockRepository.GenerateStub<IMonitorViewModel>();
            var sprintTitleViewModel = MockRepository.GenerateStub<ISprintTitleViewModel>();
            var sprintBurndownChartViewModel = MockRepository.GenerateStub<ISprintBurndownChartViewModel>();
            var sprintStatsViewModel = MockRepository.GenerateStub<ISprintStatsViewModel>();
            var backlogItemCountChartViewModel = MockRepository.GenerateStub<IBacklogItemCountChartViewModel>();
            var userStoryCountChartViewModel = MockRepository.GenerateStub<IUserStoryCountChartViewModel>();
            var sprintHoursChartViewModel = MockRepository.GenerateStub<ISprintHoursChartViewModel>();
            var unassignedTeamMember = MockRepository.GenerateStub<ITeamMemberViewModel>();
            var firstTeamMember = MockRepository.GenerateStub<ITeamMemberViewModel>();
            var secondTeamMember = MockRepository.GenerateStub<ITeamMemberViewModel>();
            var thirdTeamMember = MockRepository.GenerateStub<ITeamMemberViewModel>();
            var backlogItemsPieChartData = new ObservableCollection<PieChartValue<int>>(new[]
                                                                                            {
                                                                                                new PieChartValue<int>
                                                                                                    {
                                                                                                        Value = 1
                                                                                                    }, new PieChartValue<int>
                                                                                                           {
			                                                                            			   		Value = 1
                                                                                                           },
                                                                                                new PieChartValue<int>
                                                                                                    {
                                                                                                        Value = 1
                                                                                                    }, new PieChartValue<int>
                                                                                                           {
			                                                                            			   		Value = 1
                                                                                                           }
                                                                                            });
            var workloadPieChartData = new ObservableCollection<PieChartValue<double>>(new[]
                                                                                           {
                                                                                               new PieChartValue<double>
                                                                                                   {
                                                                                                       Value = 0.0
                                                                                                   }, new PieChartValue<double>
                                                                                                          {
			                                                                           			   		Value =
                                                                                                                  1.0
                                                                                                     },
                                                                                               new PieChartValue<double>
                                                                                                   {
                                                                                                       Value = 1.0
			                                                                           			}, new PieChartValue<double>
			                                                                           			   	{
			                                                                           			   		Value =
			                                                                           			   			1.0
                                                                                                   }
                                                                                           });


            monitorViewModel.Stub(m => m.DeploymentVersion).Return("1.0.0.78");

            sprintTitleViewModel.Stub(m => m.CurrentSprintName).Return("Sprint 4");
            sprintTitleViewModel.Stub(m => m.ProjectName).Return("scrumsprintmonitor");
            sprintTitleViewModel.Stub(m => m.PlaceholderOrientation).Return(Orientation.Horizontal);
            sprintTitleViewModel.Stub(m => m.Visibility).Return(Visibility.Visible);
            sprintTitleViewModel.Stub(m => m.SprintPercentageCovered).Return(0.75);

            // Setup Unassigned ITeamMemberViewModel

            // Setup Unassigned ITeamMemberViewModel.RemainingWorkload
            unassignedTeamMember.Stub(t => t.RemainingPotentialSprintHours).Return(10);
            unassignedTeamMember.Stub(t => t.RemainingSprintWork).Return(8);
            unassignedTeamMember.Stub(t => t.RemainingUnassignedSprintWork).Return(0);
            unassignedTeamMember.Stub(t => t.RemainingWorkItemCount).Return(3);
            unassignedTeamMember.Stub(t => t.DisplayName).Return("<Unassigned>").Repeat.Any();
            unassignedTeamMember.Stub(t => t.Team).Return("UX").Repeat.Any();

            // Setup 1st ITeamMemberViewModel
            firstTeamMember.Stub(t => t.DisplayName).Return("Pedro Sampaio").Repeat.Any();
            firstTeamMember.Stub(t => t.AvatarImageSource).Return(new DrawingImage(new GeometryDrawing
                                                                                       {
                                                                                           Geometry =
			                                                                       			new RectangleGeometry(new Rect(new Size(80, 80))),
                                                                                           Brush = Brushes.Purple
                                                                                       })).Repeat.Any();

            // Setup 1st ITeamMemberViewModel.RemainingWorkload
            firstTeamMember.Stub(t => t.RemainingPotentialSprintHours).Return(56);
            firstTeamMember.Stub(t => t.RemainingSprintWork).Return(168);
            firstTeamMember.Stub(t => t.RemainingUnassignedSprintWork).Return(4);
            firstTeamMember.Stub(t => t.IncludesFreeBusyInformation).Return(false);
            firstTeamMember.Stub(t => t.RemainingSprintWorkWithUnassigned).Return(firstTeamMember.RemainingSprintWork +
                                                                                  firstTeamMember.RemainingUnassignedSprintWork);
            firstTeamMember.Stub(t => t.RemainingWorkItemCount).Return(6);
            firstTeamMember.Stub(t => t.DoneWorkItemCount).Return(6);
            firstTeamMember.Stub(t => t.DoneSprintWork).Return(12.0);
            firstTeamMember.Stub(t => t.IsActiveInSprint).Return(true);
            firstTeamMember.Stub(t => t.BacklogItemsPieChartData).Return(backlogItemsPieChartData);
            firstTeamMember.Stub(t => t.WorkloadPieChartData).Return(workloadPieChartData);
            firstTeamMember.Stub(t => t.BurndownDataPoints).Return(new ObservableCollection<BurndownDataPoint>());

            double workDone = 0.0;
            double workRemaining = 16.0;
			for (var at = SystemTime.Now().AddDays(-15.0); at <= SystemTime.Now(); at = at.AddDays(1.0))
            {
                var dataPoint = new BurndownDataPoint
                                    {
                                        Time = at,
                                        WorkDone = workDone,
                                        WorkRemaining = workRemaining
                                    };

                workDone += 1.0;
                workRemaining -= 1.0;

                firstTeamMember.BurndownDataPoints.Add(dataPoint);
            }

            // Setup 2nd ITeamMemberViewModel
            secondTeamMember.Stub(t => t.DisplayName).Return("Eduardo Laranjeira").Repeat.Any();

            // Setup 2nd ITeamMemberViewModel.RemainingWorkload
            secondTeamMember.Stub(t => t.RemainingPotentialSprintHours).Return(56);
            secondTeamMember.Stub(t => t.RemainingSprintWork).Return(79);
            secondTeamMember.Stub(t => t.RemainingUnassignedSprintWork).Return(0);
            secondTeamMember.Stub(t => t.IncludesFreeBusyInformation).Return(false);
            secondTeamMember.Stub(t => t.RemainingSprintWorkWithUnassigned).Return(secondTeamMember.RemainingSprintWork +
                                                                                   secondTeamMember.RemainingUnassignedSprintWork);
            secondTeamMember.Stub(t => t.RemainingWorkItemCount).Return(9);
            secondTeamMember.Stub(t => t.DoneWorkItemCount).Return(6);
            secondTeamMember.Stub(t => t.DoneSprintWork).Return(12.0);
            secondTeamMember.Stub(t => t.IsActiveInSprint).Return(true);
            secondTeamMember.Stub(t => t.BacklogItemsPieChartData).Return(backlogItemsPieChartData);
            secondTeamMember.Stub(t => t.WorkloadPieChartData).Return(workloadPieChartData);

            // Setup 3rd ITeamMemberViewModel
            thirdTeamMember.Stub(t => t.DisplayName).Return("Samuel Moura").Repeat.Any();

            // Setup 3rd ITeamMemberViewModel.RemainingWorkload
            thirdTeamMember.Stub(t => t.RemainingPotentialSprintHours).Return(56);
            thirdTeamMember.Stub(t => t.RemainingSprintWork).Return(73);
            thirdTeamMember.Stub(t => t.RemainingUnassignedSprintWork).Return(1);
            thirdTeamMember.Stub(t => t.IncludesFreeBusyInformation).Return(true);
            thirdTeamMember.Stub(t => t.RemainingSprintWorkWithUnassigned).Return(thirdTeamMember.RemainingSprintWork +
                                                                                  thirdTeamMember.RemainingUnassignedSprintWork);
            thirdTeamMember.Stub(t => t.RemainingWorkItemCount).Return(8);
            thirdTeamMember.Stub(t => t.DoneWorkItemCount).Return(6);
            thirdTeamMember.Stub(t => t.DoneSprintWork).Return(12.0);
            thirdTeamMember.Stub(t => t.IsActiveInSprint).Return(true);
            thirdTeamMember.Stub(t => t.BacklogItemsPieChartData).Return(backlogItemsPieChartData);
            thirdTeamMember.Stub(t => t.WorkloadPieChartData).Return(workloadPieChartData);

            // Setup current sprint
            var teamMembersList = new List<ITeamMemberViewModel>
                                      {
                                          firstTeamMember,
                                          secondTeamMember,
                                          thirdTeamMember
                                      };
            const int backlogItemCount = 347;
            const int userStoryCount = 243;

            backlogItemCountChartViewModel.Stub(m => m.ReadyForTestWork_BacklogItemCount).Return(238);
            backlogItemCountChartViewModel.Stub(m => m.ActiveWork_BacklogItemCount).Return(36);
            backlogItemCountChartViewModel.Stub(m => m.NotDoneWork_BacklogItemCount).Return(backlogItemCount -
			                                                                                (backlogItemCountChartViewModel.ActiveWork_BacklogItemCount +
			                                                                                 backlogItemCountChartViewModel.ReadyForTestWork_BacklogItemCount));

            userStoryCountChartViewModel.Stub(m => m.ReadyForTestWork_UserStoryCount).Return(142);
            userStoryCountChartViewModel.Stub(m => m.ActiveWork_UserStoryCount).Return(49);
            userStoryCountChartViewModel.Stub(m => m.NotDoneWork_UserStoryCount).Return(userStoryCount -
                                                                                        (userStoryCountChartViewModel.ActiveWork_UserStoryCount +
                                                                                         userStoryCountChartViewModel.ReadyForTestWork_UserStoryCount));

            sprintHoursChartViewModel.Stub(m => m.ReadyForTestWork_TotalHours).Return(1694.25);
            sprintHoursChartViewModel.Stub(m => m.ActiveWork_TotalHoursDone).Return(390);
            sprintHoursChartViewModel.Stub(m => m.ActiveWork_TotalHoursRemaining).Return(375.0);
            sprintHoursChartViewModel.Stub(m => m.NotDoneWork_TotalHours).Return(712);

            sprintStatsViewModel.Stub(m => m.AvailableHours).Return(1055);
            sprintStatsViewModel.Stub(m => m.TimeIncludesFreeBusyInformation).Return(teamMembersList.All(x => x.IncludesFreeBusyInformation));
            sprintStatsViewModel.Stub(m => m.IsAheadOfSchedule).Return(sprintStatsViewModel.AvailableHours >=
                                                                       (sprintHoursChartViewModel.NotDoneWork_TotalHours +
                                                                        sprintHoursChartViewModel.ActiveWork_TotalHoursRemaining));
            sprintStatsViewModel.Stub(m => m.DifferenceToSchedule).Return(
                Math.Abs(sprintStatsViewModel.AvailableHours -
			                                                                       (sprintHoursChartViewModel.NotDoneWork_TotalHours +
			                                                                        sprintHoursChartViewModel.ActiveWork_TotalHoursRemaining)));
            sprintStatsViewModel.Stub(m => m.AverageResolutionTime).Return(sprintHoursChartViewModel.ReadyForTestWork_TotalHours /
                                                                           backlogItemCountChartViewModel.ReadyForTestWork_BacklogItemCount);

            monitorViewModel.Stub(m => m.SprintStatus).Return(SprintStatus.OK);
            monitorViewModel.Stub(m => m.SprintMode).Return(SprintMode.Sprinting);
            monitorViewModel.Stub(m => m.LastRefresh).Return(SystemTime.Now());
            monitorViewModel.Stub(m => m.LastUpdate).Return(SystemTime.Now() - TimeSpan.FromMinutes(1.5));

            var teamMembersListViewModel = MockRepository.GenerateStub<ITeamMembersListViewModel>();
            teamMembersListViewModel.Stub(m => m.UnassignedTeamMembers).Return(new List<ITeamMemberViewModel>
                                                                                   {
                                                                                       unassignedTeamMember
                                                                                   });
            teamMembersListViewModel.Stub(m => m.TeamMembersIncludingUnassigned).Return(new ObservableCollection<ITeamMemberViewModel>
                                                                                            {
                                                                                                unassignedTeamMember,
                                                                                                firstTeamMember,
                                                                                                secondTeamMember,
                                                                                                thirdTeamMember
                                                                                            });
            teamMembersListViewModel.Stub(m => m.NumberOfColumnsInGridView).Return(Math.Max(1,
                                                                                            (int)
                                                                                            Math.Sqrt(
                                                                                                teamMembersListViewModel.
                                                                                                    TeamMembersIncludingUnassigned.Count)));

            var sprintHoursPieChartData = new ObservableCollection<IWorkItemHoursPieChartData>
                                              {
                                                  CreateWorkItemHoursPieChartData(
                                                      Resources.WorkItemState_ReadyForTest,
                                                      sprintHoursChartViewModel.
                                                          ReadyForTestWork_TotalHours),
                                                  CreateWorkItemHoursPieChartData(
                                                      Resources.WorkItemState_Active_Done,
                                                      sprintHoursChartViewModel.
                                                          ActiveWork_TotalHoursDone),
                                                  CreateWorkItemHoursPieChartData(
                                                      Resources.WorkItemState_Active_Remaining,
                                                      sprintHoursChartViewModel.
                                                          ActiveWork_TotalHoursRemaining),
                                                  CreateWorkItemHoursPieChartData(
                                                      Resources.WorkItemState_NotDone,
                                                      sprintHoursChartViewModel.
                                                          NotDoneWork_TotalHours)
                                              };
            sprintHoursChartViewModel.Stub(x => x.Caption).Return("Work");
            sprintHoursChartViewModel.Stub(x => x.PieChartData).Return(sprintHoursPieChartData);
            Container.RegisterInstance(sprintHoursChartViewModel);

            var backlogItemCountPieChartData = new ObservableCollection<IWorkItemCountPieChartData>
                                                   {
                                                       CreateWorkItemCountPieChartData(
                                                           Resources.WorkItemState_ReadyForTest,
                                                           backlogItemCountChartViewModel.
                                                               ReadyForTestWork_BacklogItemCount,
                                                           sprintHoursPieChartData[0]),
                                                       CreateWorkItemCountPieChartData(string.Empty,
                                                                                       0,
                                                                                       sprintHoursPieChartData
                                                                                           [1]),
                                                       CreateWorkItemCountPieChartData(
                                                           Resources.WorkItemState_Active,
                                                           backlogItemCountChartViewModel.
                                                               ActiveWork_BacklogItemCount,
                                                           sprintHoursPieChartData[2]),
                                                       CreateWorkItemCountPieChartData(
                                                           Resources.WorkItemState_NotDone,
                                                           backlogItemCountChartViewModel.
                                                               NotDoneWork_BacklogItemCount,
                                                           sprintHoursPieChartData[3])
                                                   };
            backlogItemCountChartViewModel.Stub(x => x.Caption).Return("Backlog Items");
            backlogItemCountChartViewModel.Stub(x => x.PieChartData).Return(backlogItemCountPieChartData);
            Container.RegisterInstance(backlogItemCountChartViewModel);

            var userStoryCountPieChartData = new ObservableCollection<IWorkItemCountPieChartData>
                                                 {
                                                     CreateWorkItemCountPieChartData(
                                                         Resources.WorkItemState_ReadyForTest,
                                                         userStoryCountChartViewModel.
                                                             ReadyForTestWork_UserStoryCount,
                                                         sprintHoursPieChartData[0]),
                                                     CreateWorkItemCountPieChartData(string.Empty, 0,
                                                                                     sprintHoursPieChartData
                                                                                         [1]),
                                                     CreateWorkItemCountPieChartData(
                                                         Resources.WorkItemState_Active,
                                                         userStoryCountChartViewModel.
                                                             ActiveWork_UserStoryCount,
                                                         sprintHoursPieChartData[2]),
                                                     CreateWorkItemCountPieChartData(
                                                         Resources.WorkItemState_NotDone,
                                                         userStoryCountChartViewModel.
                                                             NotDoneWork_UserStoryCount,
                                                         sprintHoursPieChartData[3])
                                                 };
            userStoryCountChartViewModel.Stub(x => x.Caption).Return("User Stories");
            userStoryCountChartViewModel.Stub(x => x.PieChartData).Return(userStoryCountPieChartData);
            Container.RegisterInstance(userStoryCountChartViewModel);

            Container.RegisterType<IRemainingWorkStatusEvaluator, TestAssetLibrary.HardcodedRemainingWorkStatusEvaluator>(
                new ContainerControlledLifetimeManager());
            Container.RegisterInstance(teamMembersListViewModel);
            Container.RegisterInstance(sprintTitleViewModel);
            Container.RegisterInstance(sprintBurndownChartViewModel);
            Container.RegisterInstance(sprintStatsViewModel);
            Container.RegisterInstance(monitorViewModel);
        }

        private static IWorkItemHoursPieChartData CreateWorkItemHoursPieChartData(string stateName, double value)
        {
            var stub = MockRepository.GenerateStub<IWorkItemHoursPieChartData>();

            stub.StateName = stateName;
            stub.Value = value;
            stub.Stub(x => x.ValueIsHours).Return(false);

            return stub;
        }

        private static IWorkItemCountPieChartData CreateWorkItemCountPieChartData(string stateName, int value,
                                                                                  IWorkItemHoursPieChartData timeDimension)
        {
            var stub = MockRepository.GenerateStub<IWorkItemCountPieChartData>();

            stub.StateName = stateName;
            stub.Value = value;
            stub.Stub(x => x.ValueIsHours).Return(false);
            stub.TimeDimension = timeDimension;
            stub.Stub(x => x.AverageTimePerItem).Return(timeDimension.Value / value);

            return stub;
        }
    }
}